/**
 *
 */
package cn.afterturn.easypoi.excel.graph.builder;

import cn.afterturn.easypoi.excel.graph.constant.ExcelGraphElementType;
import cn.afterturn.easypoi.excel.graph.constant.ExcelGraphType;
import cn.afterturn.easypoi.excel.graph.entity.ExcelGraph;
import cn.afterturn.easypoi.excel.graph.entity.ExcelGraphElement;
import cn.afterturn.easypoi.excel.graph.entity.ExcelTitleCell;
import cn.afterturn.easypoi.util.PoiCellUtil;
import cn.afterturn.easypoi.util.PoiExcelGraphDataUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xddf.usermodel.chart.*;
import org.apache.poi.xssf.usermodel.XSSFChart;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFSheet;

import java.util.ArrayList;
import java.util.List;

/**
 * @author xfworld
 * @since 2015-12-30
 * @version 1.0
 *
 */
public class ExcelChartBuildService {
    /**
     *
     * @param workbook
     * @param graphList
     * @param build 通过实时数据行来重新计算图形定义
     * @param append
     */
    public static void createExcelChart(Workbook workbook, List<ExcelGraph> graphList, Boolean build, Boolean append) {
        if (workbook != null && graphList != null) {
            //设定默认第一个sheet为数据项
            XSSFSheet dataSource = (XSSFSheet)workbook.getSheetAt(0);
            if (dataSource != null) {
                buildTitle(dataSource, graphList);

                if (build) {
                    PoiExcelGraphDataUtil.buildGraphData(dataSource, graphList);
                }
                if (append) {
                    buildExcelChart(dataSource, dataSource, graphList);
                } else {
                    Sheet sheet = workbook.createSheet("图形界面");
                    buildExcelChart(dataSource, sheet, graphList);
                }
            }

        }
    }

    /**
     * 构建基础图形
     * @param drawing
     * @param anchor
     * @param dataSourceSheet
     * @param graph
     */
    private static void buildExcelChart(XSSFDrawing drawing, ClientAnchor anchor, XSSFSheet dataSourceSheet, ExcelGraph graph) {
        XSSFChart chart = drawing.createChart(anchor);

        XDDFChartLegend legend = chart.getOrAddLegend();
        legend.setPosition(LegendPosition.TOP_RIGHT);

        XDDFChartAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
        XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
        leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
        ExcelGraphElement categoryElement = graph.getCategory();

        List<ExcelGraphElement> valueList = graph.getValueList();
        List<XDDFNumericalDataSource<Double>> chartValueList = new ArrayList<>();
        if (valueList != null && valueList.size() > 0) {
            for (ExcelGraphElement ele : valueList) {
                XDDFNumericalDataSource<Double> source = XDDFDataSourcesFactory.fromNumericCellRange(dataSourceSheet, new CellRangeAddress(ele.getStartRowNum(), ele.getEndRowNum(), ele.getStartColNum(), ele.getEndColNum()));
                chartValueList.add(source);
            }
        }

        if (categoryElement != null && categoryElement.getElementType().equals(ExcelGraphElementType.STRING_TYPE)) {
            XDDFCategoryDataSource categoryChart = XDDFDataSourcesFactory.fromStringCellRange(dataSourceSheet, new CellRangeAddress(categoryElement.getStartRowNum(), categoryElement.getEndRowNum(), categoryElement.getStartColNum(), categoryElement.getEndColNum()));
            if (graph.getGraphType().equals(ExcelGraphType.LINE_CHART)) {
                XDDFChartData data = chart.createData(ChartTypes.LINE, bottomAxis, leftAxis);
                buildLineChartData(data, categoryChart, chartValueList, graph.getTitle());
                chart.plot(data);
            }
        } else {
            XDDFNumericalDataSource<Double> numericCategoryChart = XDDFDataSourcesFactory.fromNumericCellRange(dataSourceSheet, new CellRangeAddress(categoryElement.getStartRowNum(), categoryElement.getEndRowNum(), categoryElement.getStartColNum(), categoryElement.getEndColNum()));
            XDDFChartData data = chart.createData(ChartTypes.SCATTER, bottomAxis, leftAxis);
            buildScatterChartData(data, numericCategoryChart, chartValueList, graph.getTitle());
            chart.plot(data);
        }
    }


    /**
     * 构建多个图形对象
     * @param dataSourceSheet
     * @param targetSheet
     * @param graphList
     */
    private static void buildExcelChart(XSSFSheet dataSourceSheet, Sheet targetSheet, List<ExcelGraph> graphList) {
        int len = graphList.size();
        if (len == 1) {
            buildExcelChart(dataSourceSheet, targetSheet, graphList.get(0));
        } else {
            int drawStart = 0;
            int drawEnd = 20;
            XSSFDrawing drawing = PoiExcelGraphDataUtil.getDrawingPatriarch(targetSheet);
            for (ExcelGraph graph : graphList) {
                ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, drawStart, 15, drawEnd);
                buildExcelChart(drawing, anchor, dataSourceSheet, graph);
                drawStart = drawStart + drawEnd;
                drawEnd = drawEnd + drawEnd;
            }
        }
    }


    /**
     * 构建图形对象
     * @param dataSourceSheet
     * @param targetSheet
     * @param graph
     */
    private static void buildExcelChart(XSSFSheet dataSourceSheet, Sheet targetSheet, ExcelGraph graph) {
        XSSFDrawing drawing = PoiExcelGraphDataUtil.getDrawingPatriarch(targetSheet);
        ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 0, 15, 20);
        buildExcelChart(drawing, anchor, dataSourceSheet, graph);
    }


    /**
     * 构建Title
     * @param sheet
     * @param graph
     */
    private static void buildTitle(Sheet sheet, ExcelGraph graph) {
        int cellTitleLen = graph.getTitleCell().size();
        int titleLen = graph.getTitle().size();
        if (titleLen > 0) {

        } else {
            for (int i = 0; i < cellTitleLen; i++) {
                ExcelTitleCell titleCell = graph.getTitleCell().get(i);
                if (titleCell != null) {
                    graph.getTitle().add(PoiCellUtil.getCellValue(sheet, titleCell.getRow(), titleCell.getCol()));
                }
            }
        }
    }

    /**
     * 构建Title
     * @param sheet
     * @param graphList
     */
    private static void buildTitle(Sheet sheet, List<ExcelGraph> graphList) {
        if (graphList != null && graphList.size() > 0) {
            for (ExcelGraph graph : graphList) {
                if (graph != null) {
                    buildTitle(sheet, graph);
                }
            }
        }
    }

    /**
     *
     * @param data
     * @param categoryChart
     * @param chartValueList
     * @param title
     */
    private static void buildLineChartData(XDDFChartData data, XDDFCategoryDataSource categoryChart, List<XDDFNumericalDataSource<Double>> chartValueList, List<String> title) {
        if (chartValueList.size() == title.size()) {
            int len = title.size();
            for (int i = 0; i < len; i++) {
                //TODO 更新版本
                //data.addSerie(categoryChart, chartValueList.get(i)).setTitle(title.get(i));
            }
        } else {
            int i = 0;
            for (XDDFNumericalDataSource<Double> source : chartValueList) {
                String tempTitle = title.get(i++);
                if (StringUtils.isNotBlank(tempTitle)) {
                    data.addSeries(categoryChart, source).setTitle(tempTitle);
                } else {
                    data.addSeries(categoryChart, source);
                }
            }
        }
    }

    /**
     *
     * @param data
     * @param categoryChart
     * @param chartValueList
     * @param title
     */
    private static void buildScatterChartData(XDDFChartData data, XDDFNumericalDataSource<Double> categoryChart, List<XDDFNumericalDataSource<Double>> chartValueList, List<String> title) {
        if (chartValueList.size() == title.size()) {
            int len = title.size();
            for (int i = 0; i < len; i++) {
                data.addSeries(categoryChart, chartValueList.get(i)).setTitle(title.get(i));
            }
        } else {
            int i = 0;
            for (XDDFNumericalDataSource<Double> source : chartValueList) {
                String tempTitle = title.get(i++);
                if (StringUtils.isNotBlank(tempTitle)) {
                    data.addSeries(categoryChart, source).setTitle(tempTitle);
                } else {
                    data.addSeries(categoryChart, source);
                }
            }
        }
    }


}
